package com.zx.shiro.session;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.ValidatingSession;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import com.zx.shiro.utils.SerializableUtils;

/**
 * 自定义会话管理（session管理）
 * @author 郑雪
 * @date 2021-11-23
 */
public class MySessionDao extends EnterpriseCacheSessionDAO {
	
	/**
	 * ehcache活跃缓存名称（必须和ehcache缓存名称一致）
	 * 如果需要缓存的话，指定一个缓存的名字
	 */
	private String activeSessionCacheName;
	
	/**
	 * 指定一个session ID 生成器
	 */
	private SessionIdGenerator sessionIdGenerator;
	
	/**
	 * 存活的session集合，只用来测试，正常应该存在数据库表中
	 */
	public static List<Map<String, Object>> sessionList = new ArrayList<Map<String,Object>>();
		
	@Override
	protected Serializable doCreate(Session session) {
		
		//构建sessionId，通过sessionId保存对应的session
		Serializable sessionId = generateSessionId(session);
		//将sessionId和session捆绑，
		assignSessionId(session, sessionId);
		//添加session到数据库表中 
		//insert into t_session(id, session) values(sessionId, sessionStr);
		//session对象序列化后的字符串
		String sessionStr = SerializableUtils.serialize(session);
		//这里我先用map模仿数据库中的记录
		Map<String, Object> dbSession = new HashMap<String, Object>();
		dbSession.put("id", sessionId);
		dbSession.put("session", sessionStr);
		sessionList.add(dbSession);
		System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())
				+"---------------创建Session 如下---------------");
		System.out.println("sessionId : " + sessionId + " sessionStr : " + sessionStr + " ");
		System.out.println("host : " + session.getHost());
		System.out.println("开始时间 : " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(session.getStartTimestamp()) );
		System.out.println("最后更新时间 : " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(session.getLastAccessTime()));
		System.out.println("失效时间（毫秒） : " + session.getTimeout());
		System.out.println("MySessionDao doCreate " + sessionList.size() + " : " + sessionList);
		//返回sessionId
		return session.getId();
	}

	@Override
	protected void doDelete(Session session) {
		//缓存（活跃用户session缓存，从ehcache中获取）
		Cache<String, Deque<Serializable>> cache = getCacheManager().getCache("shiro-loginSessionCache");
		Collection<Deque<Serializable>> values = cache.values();
		System.out.println("[do Delete] ======== cache :" + values);
		for (Deque<Serializable> deque : values) {
			if(deque.contains(session.getId())){
				deque.remove(session.getId());
			}
		}
		System.out.println("[do Delete] ======== cache :" + cache.values());
		
		//从数据库表中删除session
		//delete from t_session where id = session.getId()
		for (Map<String, Object> map : sessionList) {
			if(map.get("id").equals(session.getId())){
				sessionList.remove(map);
				System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())
						+"---------------删除Session 如下---------------");
				System.out.println("sessionId : " + session.getId());
				System.out.println("host : " + session.getHost());
				System.out.println("开始时间 : " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(session.getStartTimestamp()) );
				System.out.println("最后更新时间 : " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(session.getLastAccessTime()));
				System.out.println("失效时间（毫秒） : " + session.getTimeout());
				System.out.println("MySessionDao doDelete " + sessionList.size() + " : " + sessionList);
				break;
			}
		}
		
		super.doDelete(session);
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {
		//从数据库表中查询session列表
		//select * from t_session where id= sessionId
		//return SerializableUtils.deserialize(sessionStr);
		
		System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())
				+"---------------获取Session 如下---------------");
		System.out.println("sessionId : " + sessionId );
		for (Map<String, Object> map : sessionList) {
			if(map.get("id").equals(sessionId)){
				Session session = SerializableUtils.deserialize((String)map.get("session"));
				System.out.println("host : " + session.getHost());
				System.out.println("开始时间 : " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(session.getStartTimestamp()) );
				System.out.println("最后更新时间 : " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(session.getLastAccessTime()));
				System.out.println("失效时间（毫秒） : " + session.getTimeout());
				System.out.println("MySessionDao doReadSession " + sessionList.size() + " : " + map);
				return session;
			}
		}
		
		return null;
	}

	@Override
	protected void doUpdate(Session session) {
		//如果会话过期/停止 没必要再更新了
        //这里很重要，不然导致每次接口调用完毕后，由于会话结束，导致更新了空的session到redis了。导致源码老报错session不存在
		if(session instanceof ValidatingSession
				&& ((ValidatingSession)session).isValid()){
			return;
		}
		//更新数据库表中的session
		//update t_session set session = SerializableUtils.serialize(session) where id=sessionId
		System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())
				+"---------------修改Session 如下---------------");
		System.out.println("sessionId : " + session.getId() );
		for (Map<String, Object> map : sessionList) {
			if(map.get("id").equals(session.getId())){
				Session session1 = SerializableUtils.deserialize((String)map.get("session"));
				System.out.println("MySessionDao doUpdate before : " );
				System.out.println("开始时间 : " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(session1.getStartTimestamp()) );
				System.out.println("最后更新时间 : " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(session1.getLastAccessTime()));
				System.out.println("失效时间（毫秒） : " + session1.getTimeout());
				
				String sessionStr = SerializableUtils.serialize(session);
				map.put("session", sessionStr);
				System.out.println("MySessionDao doUpdate after : " );
				System.out.println("开始时间 : " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(session.getStartTimestamp()) );
				System.out.println("最后更新时间 : " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(session.getLastAccessTime()));
				System.out.println("失效时间（毫秒） : " + session.getTimeout());
				break;
			}
		}
		super.doUpdate(session);
	}

	@Override
	public Collection<Session> getActiveSessions() {
		// TODO Auto-generated method stub
		return super.getActiveSessions();
	}

	public String getActiveSessionCacheName() {
		return activeSessionCacheName;
	}

	public void setActiveSessionCacheName(String activeSessionCacheName) {
		this.activeSessionCacheName = activeSessionCacheName;
	}

	public SessionIdGenerator getSessionIdGenerator() {
		return sessionIdGenerator;
	}

	public void setSessionIdGenerator(SessionIdGenerator sessionIdGenerator) {
		this.sessionIdGenerator = sessionIdGenerator;
	}

}
